package edu.uwm.cs552;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Observable;
import java.util.TreeMap;

import javax.swing.ImageIcon;
import javax.swing.JLabel;

public class Good extends Observable {
	private final String name;
	private final String url;
	private final ImageIcon icon;
	private int available;
	
	public static final String DEFAULT_ICON_URL = "file:lib/default.png";
	
	private static Map<String,Good> allGoods = new TreeMap<String,Good>();
	
	private Good(String n, String u, ImageIcon i, int a) {
		name = n;
		url = u;
		icon = i;
		available = a;
	}
	
	public String getName() {
		return name;
	}
	
	public ImageIcon getIcon() {
		return icon;
	}
	
	/**
	 * Find a good with the given name.
	 * @param name name to find a good for
	 * @return good with this name, or null if none created with this name.
	 */
	public static Good findGood(String name) {
		return allGoods.get(name);
	}
	
	/**
	 * Create a good with the given name, icon and availability
	 * @param name name of good, must not be null or include a comma
	 * @param url URL of icon to display, should be 32x32, may be null or "" meaning default
	 * @param available number of this good available in the game, must not be negative.
	 * @throws IOException if URL is bad or cannot be loaded
	 */
	public static void createGood(String name, String url, int available) throws IOException {
		if (name == null || name.indexOf(',') >= 0) {
			throw new IllegalArgumentException("name cannot be null or include a comma");
		}
		Good previous = allGoods.get(name);
		if (previous != null) return;
		if (available < 0) throw new IllegalArgumentException("negative availability");
		if (url == null || url.length() == 0) url = DEFAULT_ICON_URL;
		ImageIcon icon = new ImageIcon(new URL(url),name);
		Good g = new Good(name,url,icon,available);
		allGoods.put(name, g);
	}
	
	/**
	 * Read a list of goods from a stream
	 * @param br source of lines
	 * @throws IOException problem reading file
	 * @return first string that doesn't reflect a good.
	 * @throws NumberFormatException file poorly formatted.
	 */
	public static String readGoods(BufferedReader br) throws IOException, NumberFormatException  {
		String line;
		while ((line = br.readLine()).equals("GOOD")) {
			String name = br.readLine();
			int avail = Integer.parseInt(br.readLine());
			String iconurl = br.readLine();
			if (iconurl.equals("")) iconurl = DEFAULT_ICON_URL;
			createGood(name,iconurl,avail);
		}
		return line;
	}
	
	/**
	 * Write a list of goods to the output indicated.
	 * @param pw place to write goods, must not be null
	 */
	public static void writeGoods(PrintWriter pw) {
		for (Good g : allGoods.values()) {
			pw.println("GOOD");
			pw.println(g.name);
			pw.println(g.available);
			if (g.url.equals(DEFAULT_ICON_URL)) pw.println();
			else pw.println(g.url);
		}
	}
	
	/**
	 * Return an array of all goods currently in the game.
	 * @return
	 */
	public static Good[] allGoods() {
		return allGoods.values().toArray(new Good[allGoods.size()]);
	}
	
	/**
	 * Return true if the good is available.
	 * @return true if at least one entry is available.
	 */
	public boolean isAvailable() {
		return available > 0;
	}
	
	public int available() {
		return available;
	}
	
	/**
	 * Take an available good.
	 * @throws NoSuchElementException if not available
	 */
	public void grab() throws NoSuchElementException {
		if (available > 0) {
			--available;
		} else {
			throw new NoSuchElementException("none available");
		}
		setChanged();
		notifyObservers(null);
	}
	
	/**
	 * Release a good previously grabbed.
	 */
	public void release() {
		++available;
		setChanged();
		notifyObservers(null);
	}
	
	@Override 
	public String toString() {
		return name;
	}
	
	public JLabel asLabel(boolean showCount) {
		final JLabel label = new JLabel(name + (showCount ? " ("+available+")" : ""));
		/*this.addObserver(new Observer() {
			public void update(Observable o, Object x) {
				label.repaint();
			}	
		});*/
		label.setIcon(icon);
		return label;
	}
}
